package com.fom2008.db;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class FomTagProvider extends ContentProvider {

	private DatabaseHelper					dbHelper;

	private static final String				TAG					= "TagProvider";
	private static final String				DATABASE_NAME		= "fom2008.db";
	private static final int				DATABASE_VERSION	= 1;
	
	// The projection maps the public columns to the actual db columns
	private static HashMap<String, String>	TAGS_LIST_PROJECTION_MAP;

	// Used in the URI
	private static final int				TAGS				= 1;
	private static final int				TAG_ID				= 2;

	// The matcher match the URI to the above constants
	private static final UriMatcher			URI_MATCHER;

	// This is the helper class which provides the creation and update of the
	// Database.
	private static class DatabaseHelper extends SQLiteOpenHelper {
		public DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL("CREATE TABLE tags (_id INTEGER PRIMARY KEY," + "content_uri TEXT NOT NULL, "
					+ "description TEXT COLLATE LOCALIZED NOT NULL," + "latitude REAL," + "longitude REAL," + "created INTEGER,"
					+ "modified INTEGER" + ");");
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
			db.execSQL("DROP TABLE IF EXISTS tags");
			onCreate(db);
		}
	}

	@Override
	public boolean onCreate() {
		dbHelper = new DatabaseHelper(getContext());
		return true;
	}

	@Override
	public String getType(Uri uri) {
		// We map the MIME type of our data
		switch (URI_MATCHER.match(uri)) {
			case TAGS:
				return "vnd.android.cursor.dir/vnd.fom2008.tag";
			case TAG_ID:
				return "vnd.android.cursor.item/vnd.fom2008.tag";
			default:
				throw new IllegalArgumentException("Unknown URL " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
		long rowID;
		ContentValues values;
		if (initialValues != null) {
			values = new ContentValues(initialValues);
		} else {
			values = new ContentValues();
		}

		// We can only insert a tag against the base URI, no other URLs make
		// sense here
		if (URI_MATCHER.match(uri) != TAGS) {
			throw new IllegalArgumentException("Unknown URL " + uri);
		}

		// Ensure we have the desired values to be inserted
		if (values.containsKey(FomTag.Tags.TAGGED_CONTENT) == false || values.containsKey(FomTag.Tags.LATITUDE) == false
				|| values.containsKey(FomTag.Tags.LONGITUDE) == false) {
			throw new SQLException("Can not insert a new tag without content uri to be tagged, latitude or longitude");
		}

		// Insert a default value - empty description in this case
		if (values.containsKey(FomTag.Tags.DESCRIPTION) == false) {
			values.put(FomTag.Tags.DESCRIPTION, "");
		}

		// Ensure we are correct with the CP db naming and actual DB naming
		values.put("content_uri", initialValues.getAsString(FomTag.Tags.TAGGED_CONTENT));
		// And remove it from the inserted values
		values.remove(FomTag.Tags.TAGGED_CONTENT);

		SQLiteDatabase db = dbHelper.getWritableDatabase();
		rowID = db.insert("tags", "description", values);
		if (rowID > 0) {
			// This is our newly created URI
			Uri newUri = Uri.withAppendedPath(FomTag.Tags.CONTENT_URI, "" + rowID);

			// Ensure any listener on the Uri will get notified that something
			// has changed
			getContext().getContentResolver().notifyChange(newUri, null);
			return newUri;
		}

		// If we get to this point something went wrong
		throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		String[] whereArgs = null;

		switch (URI_MATCHER.match(uri)) {
			case TAGS:
				qb.setTables("tags");
				qb.setProjectionMap(TAGS_LIST_PROJECTION_MAP);
				break;

			case TAG_ID:
				qb.setTables("tags");
				qb.appendWhere("_id=?");
				// We ensure the projection is mapped
				qb.setProjectionMap(TAGS_LIST_PROJECTION_MAP);
				whereArgs = new String[] { uri.getLastPathSegment() };
				break;

			default:
				throw new IllegalArgumentException("Unknown URL " + uri);
		}

		String orderBy;
		if (TextUtils.isEmpty(sortOrder)) {
			orderBy = FomTag.Tags.SORT_ORDER;
		} else {
			orderBy = sortOrder;
		}

		SQLiteDatabase mDb = dbHelper.getReadableDatabase();
		
		// Do the actual query against the DB.
		Cursor c = qb.query(mDb, projection, null, whereArgs, null, null, orderBy);

		// Always remember to notify the system that something happened on this
		// content provider as some application can register themselves to a
		// specific URI
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		int count;
		switch (URI_MATCHER.match(uri)) {
			case TAGS:
				//  update all values that fit the where clause
				count = db.update("tags", values, selection, selectionArgs);
				break;

			case TAG_ID:
				// We want to update the specific row
				String id = uri.getPathSegments().get(1);
				// And update with new values
				count = db.update("tags", values,  FomTag.Tags._ID + "=" + id, selectionArgs);
				break;

			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
		// Don't forget to notify
		getContext().getContentResolver().notifyChange(uri, null);
		// Returns the number of rows being hit
		return count;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		int count;
		switch (URI_MATCHER.match(uri)) {
			case TAGS:
				// Delete more or less all the values - you could use a where
				// clause in order to delete specific values
				count = db.delete("tags", selection, selectionArgs);
				break;

			case TAG_ID:
				// We want to delete only the row defined by the URI. Thus get
				// the primary key from the URI
				String id = uri.getPathSegments().get(1);
				// And delete it
				count = db.delete("tags", FomTag.Tags._ID + "=" + id, selectionArgs);
				break;

			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
		// Don't forget to notify
		getContext().getContentResolver().notifyChange(uri, null);
		// Returns the number of rows being hit
		return count;
	}

	static {
		// The URI matcher matches the URI to a constant so we know how to act
		// on the database.
		URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		URI_MATCHER.addURI(FomTag.FOMTAG_AUTHORITY, "tags", TAGS);
		URI_MATCHER.addURI(FomTag.FOMTAG_AUTHORITY, "tags/#", TAG_ID);

		// The projection map will map the 'public' columns defined in FomTag to
		// the actual database table. This is useful when you want to have joins
		// for instance and to abstract the database column.
		TAGS_LIST_PROJECTION_MAP = new HashMap<String, String>();
		TAGS_LIST_PROJECTION_MAP.put(FomTag.Tags._ID, "_id");
		TAGS_LIST_PROJECTION_MAP.put(FomTag.Tags.TAGGED_CONTENT, "content_uri");
		TAGS_LIST_PROJECTION_MAP.put(FomTag.Tags.DESCRIPTION, "description");
		TAGS_LIST_PROJECTION_MAP.put(FomTag.Tags.LATITUDE, "latitude");
		TAGS_LIST_PROJECTION_MAP.put(FomTag.Tags.LONGITUDE, "longitude");
	}
}
